package edu.hawaii.myisern.action;


import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import edu.hawaii.myisern.model.MyIsernModel;
import net.sourceforge.stripes.action.Resolution;
import net.sourceforge.stripes.action.ForwardResolution;
import net.sourceforge.stripes.action.ActionBean;
import net.sourceforge.stripes.action.ActionBeanContext;
import java.util.ArrayList;

/**
 * Provides a web interface for displaying a table of elements.
 * 
 * @author Philip Johnson
 * @author Ben Karsin
 * @author Andrew Wong
 */
public class MyIsernActionBean implements ActionBean {
  /** Required by the ActionBean interface. */
  private MyIsernContext context;
  /** Our single stack instance manipulated by all webapp users. */
  private MyIsernModel isernData = MyIsernModel.getInstance();

  /** An error string, always displayed, but invisible if empty. */
  private String errorMessage = "";
  
  /** Contains flag to type of page (edit or add). */
  private String pageType;
  
  /** Commonly used literals */
  private static final String displayTable = "/displayTable.jsp";
  private static final String addVar = "Add";

//  private List<String> localData;
  
  /**
   * Sets the context. Required by the interface. 
   * @param context The ActionBeanContext to set. 
   */
  public void setContext(ActionBeanContext context) {
    this.context = (MyIsernContext) context;
  }


  /**
   * Returns the context. Required by the interface. 
   * @return the ActionBeanContext.
   */
  public MyIsernContext getContext() {
    return context;
  }

  /**
   * Retrieves the folder where data files are being read from.
   * 
   * @return Full path where data files are stored.
   */
  public String getBaseFolder() {
    return MyIsernModel.getBaseFolder();
  }

  /**
   * Returns a list of all items of given types.  If types contains C, R, and/or O,
   * it adds those items to the list.  
   *  
   * @param types Types of names to retrieve.
   * @return List of names.
   */
  public Set<String> getNames(String types) {
    Set<String> result = new TreeSet<String>();
    List<List<String>> data;

    if (types.contains("c")) {
      data = MyIsernModel.getCollaborationData().getData();

      for (List<String> item : data) {
        result.add(item.get(0));
      }
    }

    if (types.contains("r")) {
      data = MyIsernModel.getResearcherData().getData();

      for (List<String> item : data) {
        result.add(item.get(0));
      }
    }

    if (types.contains("o")) {
      data = MyIsernModel.getOrganizationData().getData();

      for (List<String> item : data) {
        result.add(item.get(0));
      }
    }

    return result;

  }

  /**
   * Retrieves an iterator for all Names in the system.
   * 
   * @return An iterator that iterates through all the names of all objects.
   */
  public Iterator<String> getAllNamesIterator() {
    return getNames("rco").iterator();
  }

  /**
   * Gets an iterator with all the organizations, used for drop-down box.
   * @return Iterator to list of organizations.
   */
  public Iterator<String> getAllOrganizationsIterator() {
    return getNames("o").iterator();    
  }
  
  /**
   * Returns the error message, which may be empty.
   *
   * @return The error message. 
   */
  public String getErrorMessage() {
    List<String> errorList = this.isernData.getSemanticErrors();
    String result = "";

    if (errorMessage != null) {
      result += errorMessage;
    }

    for (String error : errorList) {
      result += "<br>" + error;
    }

    if (!result.isEmpty()) {
      result = "<b>Semantic errors:</b>" + result;
    }
    return result;
  }

  /**
   * Provides an iterator over the header list to the page. 
   * @return The stack iterator.
   */
  public Iterator<String> getHeaderIterator() {
    Iterator<String> result;

    switch (this.context.getDisplay()) {
    case 'C':
      result = MyIsernModel.getCollaborationData().getHeader().iterator();
      break;
    case 'O':
      result = MyIsernModel.getOrganizationData().getHeader().iterator();
      break;
    case 'R':
    default:
      result = MyIsernModel.getResearcherData().getHeader().iterator();
    break;
    }

    return result;
  }

  /**
   * Provides an iterator over the header list to the page. 
   * @return The stack iterator.
   */
  public Iterator<List<String>> getDataIterator() {
    Iterator<List<String>> result;

    switch (this.context.getDisplay()) {
    case 'C':
      result = MyIsernModel.getCollaborationData().getData().iterator();
      break;
    case 'O':
      result = MyIsernModel.getOrganizationData().getData().iterator();
      break;
    case 'R':
    default:
      result = MyIsernModel.getResearcherData().getData().iterator();
    break;
    }

    return result;
  }

  /**
   * Invoked by the page to indicate the value to be added to the list.
   * @param element The element to be added to the list.
   */
  public void setAddToList(String element) {
//  this.newElement = element;
  }

  /**
   * Sets the current table to be displayed.  Changes when the page is refreshed.
   * 
   * @param item R for researcher, C for collaboration, O for organization
   */
  public void setListToDisplay(String item) {
    this.context.setDisplay(item.charAt(0));
    System.out.println("Display set to: " + item);
  }


  /**
   * Updates display of web page.
   * 
   * @return URL to refresh displayTable page.
   */
  public Resolution display() {
    return new ForwardResolution(displayTable);
  }

  /**
   * Sets the current row element in the context List.
   * @param thisRow current row being displayed.
   */
  public void setThisRow(List<String> thisRow) {
    this.context.setListRow(thisRow);
  }
  
  /**
   * Handles the action of adding or editing a researcher.
   * @return Resolution back to edit page if errors occured, else displayTable.jsp
   */
  public Resolution addResearcher() {
    List<String> newEntry = new ArrayList<String>();
    String returnError;
    
    newEntry.add(getName());
    newEntry.add(getOrgs());
    newEntry.add(getTypes());
    newEntry.add(getYears());
    newEntry.add(getOutcome());
    
    returnError = isernData.addEntry(newEntry, 'R', this.getPageType().equals(addVar));
    
    if (returnError.length() > 0) {
      this.errorMessage = returnError;
      return new ForwardResolution("/editResearcher.jsp");
    }
    this.setListToDisplay("R");
    return new ForwardResolution(displayTable);
  }
  
  /**
   * Handles the action of adding or editing an organization.
   * @return Resolution back to edit page if errors occured, else displayTable.jsp
   */
  public Resolution addOrganization() {
    List<String> newEntry = new ArrayList<String>();
    String returnError;
    
    newEntry.add(getName());
    newEntry.add(getOrgs());
    newEntry.add(getTypes());
    newEntry.add(getYears());
    newEntry.add(getOutcome());
    newEntry.add(getDesc());
    newEntry.add(getResearch());
    newEntry.add(getHomepage());
    
    returnError = isernData.addEntry(newEntry, 'O', this.getPageType().equals(addVar));
    

    if (returnError.length() > 0) {
      this.errorMessage = returnError;
      return new ForwardResolution("/editOrg.jsp");
    }
    

    this.setListToDisplay("O");
    return new ForwardResolution(displayTable);
  }
  
  /**
   * Handles the action of adding or editing a collaboration.
   * @return Resolution back to edit page if errors occured, else displayTable.jsp
   */
  public Resolution addCollaboration() {
    List<String> newEntry = new ArrayList<String>();
    String returnError;
    
    newEntry.add(getName());
    newEntry.add(getOrgs());
    newEntry.add(getTypes());
    newEntry.add(getYears());
    newEntry.add(getOutcome());
    newEntry.add(getDesc());
    
    returnError = isernData.addEntry(newEntry, 'C', this.getPageType().equals(addVar));
    
    if (returnError.length() > 0) {
      this.errorMessage = returnError;
      return new ForwardResolution("/editCollab.jsp");
    }
    

    this.setListToDisplay("C");
    return new ForwardResolution(displayTable);
  }
  
  /**
   * Handles the editing of entries.
   * 
   * @return A Resolution indicating to go to the editentry.jsp page.
   */
  public Resolution edit() {
    ForwardResolution resolution;
    this.context.setBanner("Edit");
    
    if (this.context.getDisplay() != 'O' &&
        this.context.getDisplay() != 'C' &&
        this.context.getDisplay() != 'R') {
      if (this.context.getListRow().size() == 
        MyIsernModel.getOrganizationData().getHeader().size()) {
        this.context.setDisplay('O');
      }
      if (this.context.getListRow().size() == 
        MyIsernModel.getCollaborationData().getHeader().size()) {
        this.context.setDisplay('C');
      }
      if (this.context.getListRow().size() == 
        MyIsernModel.getResearcherData().getHeader().size()) {
        this.context.setDisplay('R');
      }
    }
    
    switch (this.context.getDisplay()) {
    case 'O':
      resolution = new ForwardResolution("/editOrg.jsp");
      break;
    case 'C':
      resolution = new ForwardResolution("/editCollab.jsp");
      break;
    case 'R':
    default:
      resolution = new ForwardResolution("/editResearcher.jsp");
      break;
    }
    return resolution;
  }
  
  /**
   * Handles the adding of new entries.
   * 
   * @return A Resolution indicating to go to the editentry.jsp page.
   */
  public Resolution addElement() {
    ForwardResolution resolution;
    this.context.setBanner(addVar);
    List<String> dummyRow = new ArrayList<String>();
    for (int i = 0; i < 10; i++) {
      dummyRow.add(" ");
    }
    this.context.setListRow(dummyRow);
    switch (this.context.getDisplay()) {
    case 'R':
      resolution = new ForwardResolution("/editResearcher.jsp");
      break;
    case 'O':
      resolution = new ForwardResolution("/editOrg.jsp");
      break;
    case 'C':
    default:
      resolution = new ForwardResolution("/editCollab.jsp");
    break;
    }
    return resolution;
  }

  /**
   * Gets the current row being held in the context.
   * @return Iterator for the row.
   */
  public Iterator<String> getTestRow() {
    return this.context.getListRow().iterator();
  }
 
  /**
   * Converts a null string to an empty string.
   * @param test the string to be converted (if null).
   * @return the new string.
   */
  public String nullToEmpty(String test) {
    String temp = test;
    if (temp == null) {
      temp = " ";
    }
    return temp;
  }
  
  /**
   * Returns the name property of the context list.
   * @return the 0th element in the context list.
   */
  public String getName() {
    if (this.context.getListRow().size() < 1) {
      return " ";
    }
    return nullToEmpty(this.context.getListRow().get(0));
  }
  
  /**
   * Sets the name property of the context list.
   * @param newName to be placed in the 0th element of the context list.
   */
  public void setName(String newName) {
    this.context.getListRow().set(0, newName);
  }
  
  /**
   * Returns the Organizations property of the context list.
   * @return the 1st element in the context list.
   */
  public String getOrgs() {
    if (this.context.getListRow().size() < 2) {
      return " ";
    }
    return nullToEmpty(this.context.getListRow().get(1));
  }
  
  /**
   * Sets the Organizations property of the context list.
   * @param newOrgs to be placed in the 1st element of the context list.
   */
  public void setOrgs(String newOrgs) {
    this.context.getListRow().set(1, newOrgs);
  }
  
  /**
   * Returns the Types property of the context list.
   * @return the 2nd element in the context list.
   */
  public String getTypes() {
    if (this.context.getListRow().size() < 3) {
      return " ";
    }
    return nullToEmpty(this.context.getListRow().get(2));
  }
  
  /**
   * Sets the Types property of the context list.
   * @param newTypes to be placed in the 2nd element of the context list.
   */
  public void setTypes(String newTypes) {
    this.context.getListRow().set(2, newTypes);
  }
  
  /**
   * Returns the Years property of the context list.
   * @return the 3rd element in the context list.
   */
  public String getYears() {
    if (this.context.getListRow().size() < 4) {
      return " ";
    }
    return nullToEmpty(this.context.getListRow().get(3));
  }
  
  /**
   * Sets the Years property of the context list.
   * @param newYears to be placed in the 3rd element of the context list.
   */
  public void setYears(String newYears) {
    this.context.getListRow().set(3, newYears);
  }
  
  /**
   * Returns the Outcomes property of the context list.
   * @return the 4th element in the context list.
   */
  public String getOutcome() {
    if (this.context.getListRow().size() < 5) {
      return " ";
    }
    return nullToEmpty(this.context.getListRow().get(4));
  }
  
  /**
   * Sets the Outcome property of the context list.
   * @param newOutcome to be placed in the 4th element of the context list.
   */
  public void setOutcome(String newOutcome) {
    this.context.getListRow().set(4, newOutcome);
  }
  
  /**
   * Returns the Description property of the context list.
   * @return the 5th element in the context list.
   */
  public String getDesc() {
    if (this.context.getListRow().size() < 6) {
      return " ";
    }
    return nullToEmpty(this.context.getListRow().get(5));
  }
  
  /**
   * Sets the Description property of the context list.
   * @param newDesc to be placed in the 5th element of the context list.
   */
  public void setDesc(String newDesc) {
    this.context.getListRow().set(5, newDesc);
  }
  
  /**
   * Returns the Researchers property of the context list.
   * @return the 6th element in the context list.
   */
  public String getResearch() {
    if (this.context.getListRow().size() < 7) {
      return " ";
    }
    return nullToEmpty(this.context.getListRow().get(6));
  }
  
  /**
   * Sets the Research property of the context list.
   * @param newResearch to be placed in the 6th element of the context list.
   */
  public void setResearch(String newResearch) {
    this.context.getListRow().set(6, newResearch);
  }
  
  /**
   * Returns the Homepage property of the context list.
   * @return the 7th element in the context list.
   */
  public String getHomepage() {
    if (this.context.getListRow().size() < 8) {
      return " ";
    }
    return nullToEmpty(this.context.getListRow().get(7));
  }
  
  /**
   * Sets the Homepage property of the context list.
   * @param newHomepage to be placed in the 7th element of the context list.
   */
  public void setHomepage(String newHomepage) {
    this.context.getListRow().set(7, newHomepage);
  }
  
  /**
   * Returns the Banner message for the page (either add or edit).
   * @return either add or edit, depending on the context.
   */
  public String getBanner() {
    return this.context.getBanner();
  }
  

  /**
   * Gets the page type of the current page (add or edit).
   * @return String with current page type.
   */
  public String getPageType() {
    return pageType;
  }
  
  /**
   * Sets the page type for the current page (add or edit).
   * @param val contains either add or edit.
   */
  public void setPageType(String val) {
    pageType = val;
  }
  
  /**
   * Handles the cancel action from the edit researcher page.
   * @return Resolution back to displayTable.jsp
   */
  public Resolution resCancel() {
    this.setListToDisplay("R");
    return new ForwardResolution(displayTable);
  }
  
  /**
   * Handles the cancel action from the edit organization page.
   * @return Resolution back to displayTable.jsp
   */
  public Resolution orgCancel() {
    this.setListToDisplay("O");
    return new ForwardResolution(displayTable);
  }
  
  /**
   * Handles the cancel action from the edit collaboration page.
   * @return Resolution back to displayTable.jsp
   */
  public Resolution colCancel() {
    this.setListToDisplay("C");
    return new ForwardResolution(displayTable);
  }

}

